<template>
  <div class="api-test-container">
    <el-card class="header-card">
      <h1>AncientSeeker API 测试页面</h1>
      <p>这是一个用于测试后端所有API功能的测试页面</p>
      
      <!-- 认证状态显示 -->
      <div class="auth-status">
        <el-tag v-if="token" type="success">已登录: {{ currentUser?.username }}</el-tag>
        <el-tag v-else type="warning">未登录</el-tag>
        <el-button v-if="token" @click="logout" type="danger" size="small" style="margin-left: 10px">
          退出登录
        </el-button>
      </div>
    </el-card>

    <!-- 认证API测试 -->
    <el-card class="api-section">
      <template #header>
        <div class="card-header">
          <span>🔐 认证 API</span>
        </div>
      </template>
      
      <el-row :gutter="20">
        <!-- 用户注册 -->
        <el-col :span="8">
          <h4>用户注册</h4>
          <el-form>
            <el-form-item label="用户名">
              <el-input v-model="registerForm.username" placeholder="输入用户名" />
            </el-form-item>
            <el-form-item label="密码">
              <el-input v-model="registerForm.password" type="password" placeholder="输入密码" />
            </el-form-item>
            <el-button @click="register" type="primary" :loading="loading.register">注册</el-button>
          </el-form>
        </el-col>

        <!-- 用户登录 -->
        <el-col :span="8">
          <h4>用户登录</h4>
          <el-form>
            <el-form-item label="用户名">
              <el-input v-model="loginForm.username" placeholder="输入用户名" />
            </el-form-item>
            <el-form-item label="密码">
              <el-input v-model="loginForm.password" type="password" placeholder="输入密码" />
            </el-form-item>
            <el-button @click="login" type="success" :loading="loading.login">登录</el-button>
          </el-form>
        </el-col>

        <!-- 游客登录 -->
        <el-col :span="8">
          <h4>游客登录</h4>
          <p>无需输入用户名密码，直接以游客身份登录</p>
          <el-button @click="guestLogin" type="info" :loading="loading.guest">游客登录</el-button>
        </el-col>
      </el-row>

      <!-- 获取用户信息 -->
      <el-divider />
      <h4>获取当前用户信息</h4>
      <el-button @click="getCurrentUser" type="primary" :disabled="!token" :loading="loading.userInfo">
        获取用户信息
      </el-button>
      <div v-if="currentUser" class="result-display">
        <pre>{{ JSON.stringify(currentUser, null, 2) }}</pre>
      </div>
    </el-card>

    <!-- 书籍API测试 -->
    <el-card class="api-section">
      <template #header>
        <div class="card-header">
          <span>📚 书籍 API</span>
        </div>
      </template>

      <el-row :gutter="20">
        <el-col :span="12">
          <h4>获取书籍列表</h4>
          <el-form inline>
            <el-form-item label="分类">
              <el-input v-model="bookQuery.category" placeholder="分类" style="width: 100px" />
            </el-form-item>
            <el-form-item label="朝代">
              <el-input v-model="bookQuery.dynasty" placeholder="朝代" style="width: 100px" />
            </el-form-item>
            <el-form-item label="关键词">
              <el-input v-model="bookQuery.keyword" placeholder="关键词" style="width: 120px" />
            </el-form-item>
            <el-button @click="getBooks" type="primary" :loading="loading.books">获取书籍</el-button>
          </el-form>
          
          <div v-if="books.length > 0" class="book-list">
            <el-table :data="books" style="width: 100%" max-height="300">
              <el-table-column prop="id" label="ID" width="60" />
              <el-table-column prop="title" label="书名" />
              <el-table-column prop="author" label="作者" />
              <el-table-column prop="dynasty" label="朝代" />
              <el-table-column label="操作" width="100">
                <template #default="scope">
                  <el-button @click="getBookDetail(scope.row.id)" size="small">详情</el-button>
                </template>
              </el-table-column>
            </el-table>
          </div>
        </el-col>

        <el-col :span="12">
          <h4>书籍分类</h4>
          <el-button @click="getBookCategories" type="primary" :loading="loading.categories">
            获取分类
          </el-button>
          <div v-if="categories.length > 0" class="result-display">
            <el-tag v-for="cat in categories" :key="cat.name" style="margin: 2px">
              {{ cat.name }} ({{ cat.count }})
            </el-tag>
          </div>

          <h4>从JSON加载书籍</h4>
          <el-button @click="loadBooksFromJson" type="warning" :disabled="!token" :loading="loading.loadBooks">
            加载书籍数据
          </el-button>
        </el-col>
      </el-row>

      <!-- 书籍详情显示 -->
      <div v-if="selectedBook" class="book-detail">
        <el-divider />
        <h4>书籍详情</h4>
        <!-- 方法一：调试显示封面原始字段与拼接URL -->
        <div class="debug-line">
          <strong>DEBUG cover:</strong>
          <span>raw = {{ selectedBook.cover || '<< 空 / null >>' }}</span>
          <span style="margin-left:12px">img src = {{ selectedBook.cover ? coverImgUrl(selectedBook.cover) : 'N/A' }}</span>
        </div>
        <el-descriptions :column="2" border>
          <el-descriptions-item label="书名">{{ selectedBook.title }}</el-descriptions-item>
          <el-descriptions-item label="作者">{{ selectedBook.author }}</el-descriptions-item>
          <el-descriptions-item label="朝代">{{ selectedBook.dynasty }}</el-descriptions-item>
          <el-descriptions-item label="分类">{{ selectedBook.category }}</el-descriptions-item>
          <el-descriptions-item label="描述" :span="2">{{ selectedBook.description }}</el-descriptions-item>
          <el-descriptions-item label="章节数">{{ selectedBook.total_chapters }}</el-descriptions-item>
          <el-descriptions-item label="总字数">{{ selectedBook.total_characters }}</el-descriptions-item>
          <el-descriptions-item label="封面" :span="2">
            <div v-if="selectedBook.cover" class="cover-wrapper">
              <img :src="coverImgUrl(selectedBook.cover)" alt="cover" class="book-cover" />
            </div>
            <span v-else class="no-cover">无封面</span>
          </el-descriptions-item>
        </el-descriptions>

        <div class="book-content-actions">
          <el-button size="small" type="primary" @click="fetchBookContent(selectedBook.id)" :disabled="!token" :loading="loading.bookContent">{{ bookContent ? '刷新内容' : '获取全部内容' }}</el-button>
          <el-tag v-if="!token" type="warning" effect="plain" style="margin-left:8px">需要登录(可用游客)</el-tag>
        </div>

        <div v-if="bookContent" class="book-content-view">
          <h5>章节内容</h5>
          <el-collapse v-model="openChapters" accordion>
            <el-collapse-item
              v-for="chapter in bookContent.chapters"
              :key="chapter.id || chapter.title"
              :name="chapter.id || chapter.title"
            >
              <template #title>
                <span class="chapter-title">第{{ chapter.id }}章 {{ chapter.title }}</span>
                <span class="chapter-meta" v-if="chapter.sections"> ({{ chapter.sections.length }} 节)</span>
              </template>
              <div class="chapter-sections" v-if="chapter.sections && chapter.sections.length">
                <el-collapse v-model="openSections" class="inner-collapse">
                  <el-collapse-item
                    v-for="section in chapter.sections"
                    :key="`${chapter.id}-${section.id || section.title}`"
                    :name="`${chapter.id}-${section.id || section.title}`"
                  >
                    <template #title>
                      <span class="section-title">节 {{ section.id }} {{ section.title }}</span>
                      <span class="section-meta" v-if="section.paragraphs"> ({{ section.paragraphs.length }} 段)</span>
                    </template>
                    <div class="paragraphs" v-if="section.paragraphs && section.paragraphs.length">
                      <div
                        v-for="(p, idx) in section.paragraphs"
                        :key="idx"
                        class="paragraph-block"
                      >
                        <div class="para-original">{{ p.original }}</div>
                        <div v-if="p.translation" class="para-translation">译: {{ p.translation }}</div>
                      </div>
                    </div>
                    <div v-else class="empty-hint">无段落</div>
                  </el-collapse-item>
                </el-collapse>
              </div>
              <div v-else class="empty-hint">无节内容</div>
            </el-collapse-item>
          </el-collapse>
        </div>
        <div v-else-if="loading.bookContent" class="loading-hint">正在加载内容...</div>
      </div>
    </el-card>

    <!-- 旧 AI 聊天 API 区块已移除：统一改用下面的“会话制 AI 对话（新）” -->

    <!-- 新：会话制 AI 对话（保持与旧版历史独立） -->
    <el-card class="api-section">
      <template #header>
        <div class="card-header">
          <span>🗂 会话制 AI 对话 (新)</span>
          <el-tag type="info" effect="plain">独立于上方旧聊天历史</el-tag>
        </div>
      </template>
      <el-row :gutter="16" class="session-chat-wrapper">
        <!-- 左侧：会话列表 -->
        <el-col :span="8" class="session-list-col">
          <div class="session-toolbar">
            <el-button type="primary" size="small" :disabled="!token || sessionLoading.create" @click="createSession">新建会话</el-button>
            <el-button size="small" :loading="sessionLoading.list" @click="fetchSessions" :disabled="!token">刷新</el-button>
          </div>
          <div v-if="!token" class="empty-hint">需要登录(可游客)以查看会话</div>
          <el-scrollbar class="session-list" v-if="chatSessions.length">
            <div
              v-for="s in chatSessions"
              :key="s.id"
              :class="['session-item', { active: s.id === currentSessionId }]"
              @click="selectSession(s)"
            >
              <div class="title-row">
                <template v-if="editingSessionId !== s.id">
                  <span class="title" :title="s.title || ('会话 ' + s.id)">{{ s.title || ('会话 ' + s.id) }}</span>
                  <el-button text type="primary" size="small" @click.stop="beginRename(s)">改</el-button>
                </template>
                <template v-else>
                  <el-input v-model="editSessionTitle" size="small" class="rename-input" @keyup.enter.native="confirmRename(s)" />
                  <el-button text size="small" type="success" @click.stop="confirmRename(s)" :loading="sessionLoading.rename">✔</el-button>
                  <el-button text size="small" type="warning" @click.stop="cancelRename">✖</el-button>
                </template>
              </div>
              <div class="meta-row">
                <span class="count">{{ s.message_count }}条</span>
                <div class="actions">
                  <el-tooltip content="清空消息" placement="top"><el-button text size="small" type="warning" @click.stop="clearSessionMessages(s)" :loading="sessionLoading.clear">🧹</el-button></el-tooltip>
                  <el-tooltip content="删除会话" placement="top"><el-button text size="small" type="danger" @click.stop="deleteSession(s)" :loading="sessionLoading.delete">🗑</el-button></el-tooltip>
                </div>
              </div>
            </div>
          </el-scrollbar>
          <div v-else-if="token && !sessionLoading.list" class="empty-hint">暂无会话，点击“新建会话”开始</div>
          <div v-else-if="sessionLoading.list" class="loading-hint">加载会话中...</div>
        </el-col>

        <!-- 右侧：消息与输入 -->
        <el-col :span="16" class="session-messages-col">
          <div class="session-messages-header">
            <div>
              <strong>当前会话:</strong>
              <span v-if="currentSession">{{ currentSession.title || ('会话 ' + currentSession.id) }}</span>
              <span v-else class="empty-hint">未选择</span>
            </div>
            <div class="stream-toggle forced">流式模式（已固定）</div>
          </div>
          <div class="messages-panel" v-if="currentSessionId">
            <el-scrollbar class="messages-scroll" ref="messagesScrollRef">
              <div v-if="sessionLoading.messages" class="loading-hint">加载消息...</div>
              <div v-else-if="sessionMessages.length === 0" class="empty-hint">暂无消息，发送第一条吧</div>
              <template v-else>
                <div v-for="m in sessionMessages" :key="m.id || m._temp_id" :class="['msg-item', m.role]">
                  <div class="role">{{ m.role === 'user' ? '你' : 'AI' }}</div>
                  <div class="content" v-html="m.role === 'assistant' ? renderAssistant(m.content) : formatMessage(m.content)"></div>
                </div>
              </template>
              <div v-if="sessionStreaming" class="msg-item assistant streaming">
                <div class="role">AI</div>
                <div class="content" v-html="renderAssistant(sessionStreamBuffer || '...')"></div>
              </div>
            </el-scrollbar>
            <div class="input-area">
              <el-input
                v-model="sessionChatInput"
                type="textarea"
                :autosize="{ minRows: 2, maxRows: 4 }"
                placeholder="输入消息 (Enter 发送, Shift+Enter 换行)"
                @keydown.enter.prevent="handleSessionEnter"
                :disabled="sessionLoading.send || sessionStreaming"
              />
              <div class="input-actions">
                <el-button type="primary" size="small" @click="sendSessionMessage" :disabled="!sessionChatInput || sessionStreaming" :loading="sessionLoading.send">发送</el-button>
                <el-button size="small" @click="fetchMessages(currentSessionId)" :disabled="sessionLoading.messages || !currentSessionId">刷新消息</el-button>
              </div>
            </div>
          </div>
          <div v-else class="empty-hint" style="margin-top:10px;">请选择左侧一个会话或先创建新会话</div>
        </el-col>
      </el-row>
    </el-card>

    <!-- AI图像生成API测试 -->
    <el-card class="api-section">
      <template #header>
        <div class="card-header">
          <span>🎨 AI 图像生成 API</span>
        </div>
      </template>

      <el-row :gutter="20">
        <el-col :span="12">
          <h4>生成图像</h4>
          <el-form>
            <el-form-item label="描述">
              <el-input v-model="imageForm.prompt" type="textarea" placeholder="描述你想生成的图像" :rows="3" />
            </el-form-item>
            <el-form-item label="风格">
              <el-select v-model="imageForm.style" placeholder="选择风格">
                <el-option label="古典" value="古典" />
                <el-option label="写实" value="写实" />
                <el-option label="抽象" value="抽象" />
                <el-option label="水墨" value="水墨" />
                <el-option label="油画" value="油画" />
                <el-option label="素描" value="素描" />
              </el-select>
            </el-form-item>
            <el-form-item label="尺寸">
              <el-select v-model="imageForm.size" placeholder="尺寸" disabled>
                <el-option label="1024*1024 (方形)" value="1024*1024" />
              </el-select>
            </el-form-item>
            <el-button @click="generateImage" type="primary" :disabled="!token" :loading="loading.image">
              生成图像
            </el-button>
          </el-form>
          <!-- 显示生成的图像 -->
          <div v-if="generatedImage" class="generated-image-section">
            <el-divider />
            <h5>生成结果</h5>
            <div class="image-result">
              <el-image 
                :src="getImageUrl(generatedImage.image_url)" 
                fit="contain" 
                style="width: 100%; max-width: 400px; max-height: 400px; border-radius: 8px;"
                :preview-src-list="[getImageUrl(generatedImage.image_url)]"
                preview-teleported
              >
                <template #error>
                  <div class="image-error">
                    <el-icon><Picture /></el-icon>
                    <p>图像加载失败</p>
                    <p>原始URL: {{ generatedImage.image_url }}</p>
                  </div>
                </template>
              </el-image>
              <div class="image-info">
                <p><strong>提示词:</strong> {{ generatedImage.prompt }}</p>
                <p><strong>风格:</strong> {{ generatedImage.style }}</p>
                <p><strong>生成时间:</strong> {{ generatedImage.generation_time?.toFixed(2) || 0 }}秒</p>
                <el-button 
                  @click="downloadImage(generatedImage.image_url, generatedImage.prompt)" 
                  type="success" 
                  size="small"
                  style="margin-top: 10px;"
                >
                  下载图像
                </el-button>
              </div>
            </div>
          </div>
        </el-col>

        <el-col :span="12">
          <h4>图像历史</h4>
          <div style="margin-bottom: 15px;">
            <el-button @click="getImageHistory" type="info" :disabled="!token" :loading="loading.imageHistory">
              获取图像历史
            </el-button>
            <el-button @click="getImageStats" type="success" :disabled="!token" :loading="loading.imageStats" style="margin-left: 10px;">
              获取统计
            </el-button>
          </div>

          <!-- 图像统计信息 -->
          <div v-if="imageStats" class="image-stats">
            <h5>图像统计:</h5>
            <el-descriptions :column="1" size="small" border>
              <el-descriptions-item label="总图像数">{{ imageStats.total_images }}</el-descriptions-item>
              <el-descriptions-item label="收藏图像数">{{ imageStats.favorite_images }}</el-descriptions-item>
            </el-descriptions>
            <div v-if="imageStats.style_stats && imageStats.style_stats.length > 0" style="margin-top: 10px;">
              <h6>风格统计:</h6>
              <el-tag 
                v-for="stat in imageStats.style_stats" 
                :key="stat.style" 
                style="margin: 2px 5px 2px 0;"
                size="small"
              >
                {{ stat.style }}: {{ stat.count }}
              </el-tag>
            </div>
          </div>

          <!-- 图像历史列表 -->
          <div v-if="imageHistory.length > 0" class="image-history-section">
            <el-divider />
            <h5>历史图像 (显示最近5张)</h5>
            <div class="image-history-grid">
              <div 
                v-for="image in imageHistory.slice(0, 5)" 
                :key="image.id" 
                class="history-image-item"
              >
                <el-image 
                  :src="getImageUrl(image.image_url)" 
                  fit="cover" 
                  style="width: 100px; height: 100px; border-radius: 4px;"
                  :preview-src-list="[getImageUrl(image.image_url)]"
                  preview-teleported
                >
                  <template #error>
                    <div class="image-error-small">
                      <el-icon><Picture /></el-icon>
                    </div>
                  </template>
                </el-image>
                <div class="image-item-info">
                  <p class="image-prompt">{{ image.prompt.slice(0, 30) }}{{ image.prompt.length > 30 ? '...' : '' }}</p>
                  <p class="image-meta">
                    <el-tag size="small" type="info">{{ image.style }}</el-tag>
                    <span class="image-date">{{ new Date(image.created_at).toLocaleDateString() }}</span>
                  </p>
                  <div class="image-actions">
                    <el-button 
                      @click="toggleImageFavorite(image.id, image.is_favorite)" 
                      :type="image.is_favorite ? 'warning' : 'default'" 
                      size="small"
                    >
                      {{ image.is_favorite ? '取消收藏' : '收藏' }}
                    </el-button>
                    <el-button 
                      @click="deleteImage(image.id)" 
                      type="danger" 
                      size="small"
                      style="margin-left: 5px;"
                    >
                      删除
                    </el-button>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </el-col>
      </el-row>
    </el-card>

    

    <!-- 结果显示区域 -->
    <el-card v-if="lastResponse" class="result-section">
      <template #header>
        <div class="card-header">
          <span>📄 最后一次API响应</span>
          <el-button @click="lastResponse = null" type="text" style="float: right">清除</el-button>
        </div>
      </template>
      <pre class="json-response">{{ JSON.stringify(lastResponse, null, 2) }}</pre>
    </el-card>
  </div>
</template>

<script setup>
import { ref, reactive, onMounted, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import axios from 'axios'
import { Picture } from '@element-plus/icons-vue'
import { STORAGE_TOKEN_KEY, setToken, getToken, removeToken } from '@/utils/auth'
import apiBaseClient from '@/api/http'
import { renderMarkdown } from '@/utils/markdownRenderer'

// 复用全局 http 实例，避免重复拦截器与 /api 重复
const api = apiBaseClient

// 状态管理
const token = ref(getToken())
const currentUser = ref(null)
const lastResponse = ref(null)

// 新增：书籍完整内容与折叠状态
const bookContent = ref(null)
const openChapters = ref([])
const openSections = ref([])

// 加载状态
const loading = reactive({
  register: false,
  login: false,
  guest: false,
  userInfo: false,
  books: false,
  categories: false,
  loadBooks: false,
  bookContent: false,
  chat: false,
  interpret: false,
  quiz: false,
  history: false,
  clearHistory: false,
  image: false,
  imageHistory: false,
  imageStats: false,
  
})

// 表单数据
const registerForm = reactive({
  username: '',
  password: ''
})

const loginForm = reactive({
  username: '',
  password: ''
})

const bookQuery = reactive({
  category: '',
  dynasty: '',
  keyword: ''
})

const chatForm = reactive({
  message: '',
  book_id: ''
})

const interpretForm = reactive({
  passage: '',
  book_id: '',
  question: ''
})

const quizForm = reactive({
  book_id: '',
  difficulty: 'medium',
  question_count: 3
})

const imageForm = reactive({
  prompt: '',
  style: '古典',
  size: '1024*1024'
})


// 数据存储
const books = ref([])
const categories = ref([])
const selectedBook = ref(null)
const chatResponse = ref(null)
const interpretResponse = ref(null)
const chatHistory = ref([])
const generatedImage = ref(null)  // 最新生成单张
const imageHistory = ref([])      // 历史列表
const imageStats = ref(null)
// 兼容旧字段：保留 generatedImages 但不再使用（避免引用报错）
const generatedImages = ref([])


// 设置请求拦截器
api.interceptors.request.use(config => {
  if (token.value) {
    config.headers.Authorization = `Bearer ${token.value}`
  }
  return config
})

// 设置响应拦截器
api.interceptors.response.use(
  response => {
    lastResponse.value = response.data
    return response
  },
  error => {
    console.error('API Error:', error)
    ElMessage.error(error.response?.data?.detail || error.message || '请求失败')
    lastResponse.value = error.response?.data || { error: error.message }
    throw error
  }
)

// API调用函数

// 认证相关
const register = async () => {
  loading.register = true
  try {
  const response = await api.post('/api/auth/register', registerForm)
    ElMessage.success('注册成功')
    registerForm.username = ''
    registerForm.password = ''
  } catch (error) {
    // 错误已在拦截器中处理
  } finally {
    loading.register = false
  }
}

const login = async () => {
  loading.login = true
  try {
  const response = await api.post('/api/auth/login', loginForm)
  token.value = response.data.access_token
  setToken(token.value)
    ElMessage.success('登录成功')
    await getCurrentUser()
    loginForm.username = ''
    loginForm.password = ''
  } catch (error) {
    // 错误已在拦截器中处理
  } finally {
    loading.login = false
  }
}

const guestLogin = async () => {
  loading.guest = true
  try {
  const response = await api.post('/api/auth/guest')
  token.value = response.data.access_token
  setToken(token.value)
    ElMessage.success(`游客登录成功，用户名: ${response.data.username}`)
    await getCurrentUser()
  } catch (error) {
    // 错误已在拦截器中处理
  } finally {
    loading.guest = false
  }
}

const getCurrentUser = async () => {
  if (!token.value) return
  loading.userInfo = true
  try {
  const response = await api.get('/api/auth/me')
    currentUser.value = response.data
  } catch (error) {
    // 错误已在拦截器中处理
  } finally {
    loading.userInfo = false
  }
}

const logout = () => {
  token.value = null
  currentUser.value = null
  removeToken()
  ElMessage.success('已退出登录')
}

// 书籍相关
const getBooks = async () => {
  loading.books = true
  try {
    const params = {}
    if (bookQuery.category) params.category = bookQuery.category
    if (bookQuery.dynasty) params.dynasty = bookQuery.dynasty
    if (bookQuery.keyword) params.keyword = bookQuery.keyword
    
  const response = await api.get('/api/books/', { params })
    books.value = response.data.items || []
    ElMessage.success(`获取到 ${books.value.length} 本书籍`)
  } catch (error) {
    // 错误已在拦截器中处理
  } finally {
    loading.books = false
  }
}

const getBookDetail = async (bookId) => {
  try {
    const response = await api.get(`/api/books/${bookId}`)
    selectedBook.value = response.data
    ElMessage.success('获取书籍详情成功')
    // 选择新书后清空之前的章节内容
    bookContent.value = null
  } catch (error) {
    // 错误已在拦截器中处理
  }
}

// 获取整本书的章节/节/段落内容（需要登录或游客身份）
const fetchBookContent = async (bookId) => {
  if (!token.value) {
    ElMessage.warning('请先登录（可使用游客登录）再获取内容')
    return
  }
  loading.bookContent = true
  try {
    const response = await api.get(`/api/books/${bookId}/content`)
    bookContent.value = response.data
    // 默认展开前两个章节
    openChapters.value = (bookContent.value.chapters || []).slice(0, 2).map(ch => ch.id || ch.title)
    ElMessage.success('书籍内容加载完成')
  } catch (error) {
    // 统一错误拦截
  } finally {
    loading.bookContent = false
  }
}

const getBookCategories = async () => {
  loading.categories = true
  try {
  const response = await api.get('/api/books/categories/')
    categories.value = response.data || []
    ElMessage.success(`获取到 ${categories.value.length} 个分类`)
  } catch (error) {
    // 错误已在拦截器中处理
  } finally {
    loading.categories = false
  }
}

const loadBooksFromJson = async () => {
  loading.loadBooks = true
  try {
  const response = await api.post('/api/books/load-from-json')
    ElMessage.success(response.data.message)
  } catch (error) {
    // 错误已在拦截器中处理
  } finally {
    loading.loadBooks = false
  }
}

// 旧 /api/ai/* 聊天相关已废弃，以下占位避免调用
const chatStreamEnabled = ref(true)
const chatStreaming = ref(false)
const chatStreamBuffer = ref('')

const chatWithAI = async () => {
  ElMessage.info('已迁移到“会话制 AI 对话 (新)”，此旧接口已移除')
}



const interpretText = async () => {
  ElMessage.info('旧 interpret 接口已移除，后续将以会话插件形式提供')
}



const generateQuiz = async () => {
  ElMessage.info('旧 quiz 接口已移除，后续将以会话插件形式提供')
}

const getChatHistory = async () => {
  ElMessage.info('旧聊天历史接口已移除，使用会话列表代替')
}

const clearChatHistory = async () => {
  ElMessage.info('旧聊天历史接口已移除')
}

// AI图像相关
// 图像生成
const generateImage = async () => {
  loading.image = true
  try {
    const payload = { ...imageForm }
    if (payload.size.includes('x')) payload.size = payload.size.replace(/x/gi, '*')
  const response = await api.post('/api/ai/generate-image', payload)
    generatedImage.value = response.data
    // 主动探测新图片可访问性，处理潜在文件系统写入与静态挂载延迟
    if (generatedImage.value?.image_url) {
      const testUrl = getImageUrl(generatedImage.value.image_url) + '?t=' + Date.now()
      try {
        const headResp = await fetch(testUrl, { method: 'GET', cache: 'no-store' })
        if (!headResp.ok) {
          console.warn('[AIImage] 初次拉取失败，稍后重试一次', headResp.status)
          // 轻微延迟再试（部分平台 I/O 延迟）
          await new Promise(r => setTimeout(r, 500))
          await fetch(testUrl, { method: 'GET', cache: 'no-store' }).catch(()=>{})
        }
      } catch (probeErr) {
        console.warn('[AIImage] 探测图片异常', probeErr)
      }
    }
    ElMessage.success('图像生成成功')
    // 生成后自动刷新历史（若已经加载过）
    if (imageHistory.value.length) await getImageHistory()
  } catch (e) {
    // 统一拦截
  } finally {
    loading.image = false
  }
}

// 获取历史
const getImageHistory = async () => {
  loading.imageHistory = true
  try {
  const response = await api.get('/api/ai/images')
    imageHistory.value = response.data || []
    ElMessage.success(`获取到 ${imageHistory.value.length} 张图像`)
  } catch (e) {} finally { loading.imageHistory = false }
}

// 统计
const getImageStats = async () => {
  loading.imageStats = true
  try {
  const response = await api.get('/api/ai/images/stats')
    imageStats.value = response.data
    ElMessage.success('获取图像统计成功')
  } catch (e) {} finally { loading.imageStats = false }
}

// 收藏切换
const toggleImageFavorite = async (imageId, isFav) => {
  try {
  const resp = await api.post(`/api/ai/images/${imageId}/favorite`)
    ElMessage.success(resp.data.message || '已更新')
    const idx = imageHistory.value.findIndex(i => i.id === imageId)
    if (idx !== -1) imageHistory.value[idx].is_favorite = !isFav
    if (imageStats.value) await getImageStats()
  } catch (e) {}
}

// 删除
const deleteImage = async (imageId) => {
  try {
    await ElMessageBox.confirm('确定要删除这张图像吗？', '确认删除', {
      confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning'
    })
  await api.delete(`/api/ai/images/${imageId}`)
    imageHistory.value = imageHistory.value.filter(i => i.id !== imageId)
    ElMessage.success('图像删除成功')
    if (imageStats.value) await getImageStats()
  } catch (e) { if (e === 'cancel') return }
}

// URL 处理（动态基址，支持局域网访问）
// 计算后端 API 基础地址：优先使用 VITE_API_BASE，其次使用当前 host + 推断端口
const computeApiBase = () => {
  try {
    const env = (import.meta.env?.VITE_API_BASE || '').trim()
    if (env) return env.replace(/\/+$/, '')
    const { protocol, hostname, port } = window.location
    // 前端常见开发端口 -> 推断后端端口
    const backendPort = (port === '5173' || port === '4173') ? '8000' : port
    return `${protocol}//${hostname}${backendPort ? ':' + backendPort : ''}`
  } catch {
    return ''
  }
}
const apiBase = computeApiBase()
console.debug('[ApiTest] apiBase resolved =', apiBase)

// 书籍封面 URL 构造
// 开发阶段：直接使用当前页面 origin 来访问 /static 资源，便于通过 Vite 代理 (5173 -> 8000)
// 返回值示例： http://<LAN_IP>:5173/static/xxx.png
const coverImgUrl = (cover) => {
  if (!cover) return ''
  const origin = (typeof window !== 'undefined') ? window.location.origin : ''
  if (cover.startsWith('http')) return cover
  if (cover.startsWith('/')) return `${origin}${cover}`
  return `${origin}/static/${cover}`
}

// 通用图像（AI 生成等）URL 构造（同上：优先使用当前 origin）
const getImageUrl = (imageUrl) => {
  if (!imageUrl) return ''
  const origin = (typeof window !== 'undefined') ? window.location.origin : ''
  let finalUrl = ''
  if (imageUrl.startsWith('http')) {
    finalUrl = imageUrl
  } else if (imageUrl.startsWith('/')) {
    finalUrl = `${origin}${imageUrl}`
  } else {
    finalUrl = `${origin}/static/${imageUrl}`
  }
  if (typeof window !== 'undefined' && window?.__AI_IMAGE_DEBUG__ !== true) {
    window.__AI_IMAGE_DEBUG__ = true
    console.debug('[ApiTest] sample imageUrl mapping (origin mode):', { raw: imageUrl, finalUrl })
  }
  return finalUrl
}

// 下载
const downloadImage = async (imageUrl, prompt) => {
  try {
    const fullUrl = getImageUrl(imageUrl)
    const res = await fetch(fullUrl)
    const blob = await res.blob()
    const url = window.URL.createObjectURL(blob)
    const a = document.createElement('a')
    a.href = url
    a.download = `${(prompt || 'image').slice(0,20)}_generated.jpg`
    document.body.appendChild(a)
    a.click()
    window.URL.revokeObjectURL(url)
    document.body.removeChild(a)
    ElMessage.success('图像下载开始')
  } catch (e) { ElMessage.error('图像下载失败') }
}

// 旧探索相关接口已移除，测试面板对应入口与调用已删除

// 组件挂载时获取用户信息
onMounted(() => {
  if (token.value) {
    getCurrentUser()
  }
})

// 帮助函数：将后端返回的 /static/... 路径补上 /api 前缀以适配开发代理
function resolveImageUrl(url) { if (!url) return ''; if (url.startsWith('/')) return '/api' + url; return url }

// 调试：监听 generatedImage 变化输出到控制台
watch(generatedImage, (val) => { if (val) { console.debug('[AIImage][Generated]', val); } });

// =============================
// 会话制聊天（新）
// =============================
const chatSessions = ref([])
const currentSessionId = ref(null)
const currentSession = ref(null)
const sessionMessages = ref([])
const sessionChatInput = ref('')
// 会话制聊天强制流式模式
const sessionStreamEnabled = ref(true) // 保留引用以最小侵入；始终为 true
const sessionStreaming = ref(false)
const sessionStreamBuffer = ref('')
const editingSessionId = ref(null)
const editSessionTitle = ref('')
const messagesScrollRef = ref(null)

const sessionLoading = reactive({
  list: false,
  create: false,
  messages: false,
  send: false,
  rename: false,
  delete: false,
  clear: false,
})

const fetchSessions = async () => {
  if (!token.value) return
  sessionLoading.list = true
  try {
  const resp = await api.get('/api/chat/sessions')
    // 后端返回形如 { sessions: [...], total: n }
    const arr = resp.data.sessions || resp.data.items || []
    chatSessions.value = Array.isArray(arr) ? arr : []
  } catch (e) { /* handled globally */ } finally { sessionLoading.list = false }
}

const createSession = async () => {
  if (!token.value) return
  sessionLoading.create = true
  try {
  const resp = await api.post('/api/chat/sessions', { title: '' })
    const s = resp.data
    chatSessions.value.unshift(s)
    selectSession(s)
    // 再次拉取以确保与后端结构完全一致（防止字段缺失导致渲染判断为空）
    fetchSessions()
    ElMessage.success('会话创建成功')
  } catch (e) {} finally { sessionLoading.create = false }
}

const selectSession = (s) => {
  currentSessionId.value = s.id
  currentSession.value = s
  fetchMessages(s.id)
}

const fetchMessages = async (sessionId) => {
  if (!sessionId) return
  sessionLoading.messages = true
  try {
    const resp = await api.get(`/api/chat/sessions/${sessionId}/messages`)
    const arr = resp.data.messages || resp.data.items || []
    sessionMessages.value = Array.isArray(arr) ? arr : []
    scrollMessagesToEnd()
  } catch (e) {} finally { sessionLoading.messages = false }
}

const scrollMessagesToEnd = () => {
  // 简单延迟等待 DOM 更新
  requestAnimationFrame(() => {
    const wrap = document.querySelector('.messages-scroll .el-scrollbar__wrap')
    if (wrap) wrap.scrollTop = wrap.scrollHeight
  })
}

const handleSessionEnter = (e) => {
  if (e.shiftKey) { // 换行
    const ta = e.target
    const pos = ta.selectionStart
    sessionChatInput.value = sessionChatInput.value.slice(0,pos) + '\n' + sessionChatInput.value.slice(pos)
    requestAnimationFrame(scrollMessagesToEnd)
    return
  }
  sendSessionMessage()
}

const sendSessionMessage = async () => {
  if (!currentSessionId.value || !sessionChatInput.value) return
  sessionLoading.send = true
  sessionStreaming.value = false
  sessionStreamBuffer.value = ''
  const userContent = sessionChatInput.value
  const tempId = 'temp-' + Date.now()
  sessionMessages.value.push({ id: tempId, _temp_id: tempId, role: 'user', content: userContent })
  scrollMessagesToEnd()
  try {
    // 强制流式
    sessionStreaming.value = true
    const origin = window.location.origin
    const base = api?.defaults?.baseURL || (origin.endsWith('/api') ? origin : origin + '/api')
    const bearer = token.value ? `Bearer ${token.value}` : ''
    const resp = await fetch(`${base}/chat/sessions/${currentSessionId.value}/messages`, {
      method: 'POST',
      headers: { 'Content-Type':'application/json', 'Accept':'text/event-stream', 'Authorization': bearer },
      body: JSON.stringify({ content: userContent, stream: true })
    })
    if (!resp.ok || !resp.body) { ElMessage.error('流式请求失败'); return }
    sessionChatInput.value = ''
    const reader = resp.body.getReader()
    const decoder = new TextDecoder('utf-8')
    let partial = ''
    while (true) {
      const { value, done } = await reader.read()
      if (done) break
      const text = decoder.decode(value, { stream: true })
      partial += text
      const frames = partial.split(/\n\n/)
      partial = frames.pop() || ''
      for (const frame of frames) {
        const line = frame.trim()
        if (!line || !line.startsWith('data:')) continue
        const payload = line.slice(5).trim()
        if (payload === '[DONE]') { partial='' ; break }
        if (payload.startsWith('[ERROR]')) { sessionStreamBuffer.value += '\n' + payload; continue }
        sessionStreamBuffer.value += payload
        scrollMessagesToEnd()
      }
    }
    // 完成后固化 assistant 消息
    sessionMessages.value.push({ role: 'assistant', content: sessionStreamBuffer.value, id: 'a-' + Date.now() })
    sessionStreamBuffer.value = ''
    sessionStreaming.value = false
    updateSessionCounters(currentSessionId.value, +2)
    scrollMessagesToEnd()
  } catch (e) {
    ElMessage.error('发送失败')
  } finally {
    sessionLoading.send = false
  }
}

const updateSessionCounters = (sessionId, delta) => {
  const idx = chatSessions.value.findIndex(s => s.id === sessionId)
  if (idx !== -1) {
    const current = Number(chatSessions.value[idx].message_count || 0)
    chatSessions.value[idx].message_count = current + delta
  }
}

// 重命名流程
const beginRename = (s) => {
  editingSessionId.value = s.id
  editSessionTitle.value = s.title || ''
}
const cancelRename = () => { editingSessionId.value = null; editSessionTitle.value = '' }
const confirmRename = async (s) => {
  if (!editingSessionId.value) return
  sessionLoading.rename = true
  try {
    await api.patch(`/api/chat/sessions/${s.id}`, { title: editSessionTitle.value })
    s.title = editSessionTitle.value
    ElMessage.success('重命名成功')
    if (currentSessionId.value === s.id) currentSession.value = s
    cancelRename()
  } catch (e) {} finally { sessionLoading.rename = false }
}

// 删除会话
const deleteSession = async (s) => {
  try {
    await ElMessageBox.confirm('确定删除该会话及其所有消息？', '删除确认', { type: 'warning' })
    sessionLoading.delete = true
    await api.delete(`/api/chat/sessions/${s.id}`)
    chatSessions.value = chatSessions.value.filter(c => c.id !== s.id)
    if (currentSessionId.value === s.id) { currentSessionId.value = null; currentSession.value = null; sessionMessages.value = [] }
    ElMessage.success('会话已删除')
  } catch (e) { if (e === 'cancel') return } finally { sessionLoading.delete = false }
}

// 清空消息
const clearSessionMessages = async (s) => {
  try {
    await ElMessageBox.confirm('确定清空该会话的所有消息？', '清空确认', { type: 'warning' })
    sessionLoading.clear = true
    await api.delete(`/api/chat/sessions/${s.id}/messages`)
    if (currentSessionId.value === s.id) sessionMessages.value = []
    s.message_count = 0
    ElMessage.success('已清空')
  } catch (e) { if (e === 'cancel') return } finally { sessionLoading.clear = false }
}

// 简单 markdown/换行处理（安全起见仅处理换行与基本转义）
const escapeHtml = (str='') => str
  .replace(/&/g,'&amp;')
  .replace(/</g,'&lt;')
  .replace(/>/g,'&gt;')
  .replace(/"/g,'&quot;')
  .replace(/'/g,'&#39;')

const formatMessage = (text='') => {
  const safe = escapeHtml(text)
  return safe.replace(/\n/g,'<br/>')
}

// assistant markdown 渲染 (markdown-it + highlight.js)
const renderAssistant = (text='') => renderMarkdown(text)

// 初始自动加载会话列表（若已登录）
onMounted(() => { if (token.value) fetchSessions() })



</script>

<style scoped>
.api-test-container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
}

.header-card {
  margin-bottom: 20px;
  text-align: center;
}

.auth-status {
  margin-top: 15px;
}

.api-section {
  margin-bottom: 20px;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-weight: bold;
  font-size: 16px;
}

.result-display {
  margin-top: 15px;
  padding: 10px;
  background-color: #f5f5f5;
  border-radius: 4px;
  max-height: 200px;
  overflow-y: auto;
}

.book-list {
  margin-top: 15px;
}

.book-detail {
  margin-top: 20px;
}

.debug-line {
  font-size: 12px;
  color: #666;
  background: #f8f8f8;
  padding: 4px 8px;
  border: 1px dashed #ddd;
  border-radius: 4px;
  margin-bottom: 10px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.cover-wrapper {
  width: 140px;
  height: 180px;
  overflow: hidden;
  border: 1px solid #ddd;
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #fafafa;
}

.book-cover {
  max-width: 100%;
  max-height: 100%;
  object-fit: cover;
}

.book-content-actions {
  margin: 12px 0 8px;
}

.book-content-view {
  margin-top: 10px;
  border: 1px solid #e5e5e5;
  border-radius: 6px;
  padding: 10px 14px;
  background: #fff;
}

.chapter-title { font-weight: 600; }
.section-title { font-weight: 500; }
.chapter-meta, .section-meta { color: #888; margin-left: 4px; font-size: 12px; }

.paragraph-block { padding: 6px 0; border-bottom: 1px dashed #eee; }
.paragraph-block:last-child { border-bottom: none; }
.para-original { font-family: 'STKaiti', 'KaiTi', serif; font-size: 14px; line-height: 1.6; }
.para-translation { margin-top: 2px; color: #555; font-size: 12px; }
.empty-hint { color: #999; font-size: 12px; padding: 4px 0; }
.loading-hint { color: #666; font-style: italic; margin-top: 8px; }

.chat-response,
.interpret-response,


.response-content {
  white-space: pre-wrap;
  line-height: 1.6;
}



.chat-history {
  margin-top: 15px;
  max-height: 300px;
  overflow-y: auto;
}

.image-stats {
  margin-top: 15px;
  padding: 10px;
  background-color: #f0f9ff;
  border-radius: 4px;
}

/* 图像显示相关样式（从 copy 同步） */
.generated-image-section { margin-top: 20px; }
.image-result { display: flex; flex-direction: column; align-items: center; gap: 15px; }
.image-info { text-align: center; max-width: 400px; }
.image-info p { margin: 5px 0; word-break: break-word; }
.image-error { display:flex; flex-direction:column; align-items:center; justify-content:center; height:200px; background:#f5f5f5; border-radius:8px; color:#999; }
.image-error-small { display:flex; align-items:center; justify-content:center; width:100%; height:100%; background:#f5f5f5; border-radius:4px; color:#999; }
.image-history-section { margin-top:20px; }
.image-history-grid { display:grid; grid-template-columns:1fr; gap:15px; max-height:400px; overflow-y:auto; }
.history-image-item { display:flex; gap:10px; padding:10px; border:1px solid #e0e0e0; border-radius:8px; background:#fafafa; }
.image-item-info { flex:1; display:flex; flex-direction:column; justify-content:space-between; }
.image-prompt { font-size:12px; font-weight:bold; margin:0 0 5px 0; line-height:1.4; }
.image-meta { display:flex; align-items:center; justify-content:space-between; margin:5px 0; }
.image-date { font-size:11px; color:#666; margin-left:8px; }
.image-actions { display:flex; gap:5px; }
.image-actions .el-button { padding:4px 8px; font-size:11px; }

.result-section {
  margin-top: 20px;
}

.json-response {
  background-color: #f5f5f5;
  padding: 15px;
  border-radius: 4px;
  max-height: 400px;
  overflow-y: auto;
  font-size: 12px;
  line-height: 1.4;
}

/* 会话制聊天样式 */
.session-chat-wrapper { min-height: 420px; }
.session-list-col { border-right: 1px solid #eee; }
.session-toolbar { display:flex; gap:6px; margin-bottom:8px; }
.session-list { max-height:380px; }
.session-item { padding:6px 8px; border:1px solid #e5e5e5; border-radius:6px; margin-bottom:6px; cursor:pointer; background:#fafafa; transition: background .15s; }
.session-item.active { background:#e6f7ff; border-color:#91d5ff; }
.session-item:hover { background:#f0f9ff; }
.session-item .title-row { display:flex; align-items:center; justify-content:space-between; gap:4px; }
.session-item .title { font-weight:600; font-size:13px; flex:1; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.session-item .meta-row { display:flex; align-items:center; justify-content:space-between; margin-top:4px; font-size:11px; }
.session-item .actions { display:flex; gap:4px; }
.rename-input { width:120px; }

.session-messages-col { display:flex; flex-direction:column; }
.session-messages-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:6px; }
.messages-panel { display:flex; flex-direction:column; height:380px; }
.messages-scroll { flex:1; padding:6px 4px; border:1px solid #eee; border-radius:6px; background:#fff; }
.msg-item { margin:6px 0; display:flex; gap:6px; }
.msg-item .role { font-size:12px; font-weight:600; width:32px; text-align:right; color:#555; }
.msg-item.user .content { background:#f5f5f5; }
.msg-item.assistant .content { background:#e8f3ff; }
.msg-item.streaming .content { opacity:0.8; }
.msg-item .content { flex:1; padding:6px 8px; border-radius:4px; font-size:13px; line-height:1.5; word-break:break-word; }
.input-area { margin-top:8px; display:flex; flex-direction:column; gap:6px; }
.input-actions { display:flex; gap:8px; justify-content:flex-end; }
.stream-toggle.forced { font-size:12px; color:#555; background:#f5faff; padding:4px 8px; border:1px solid #d9ecff; border-radius:4px; }

/* Markdown 基础样式 */
.msg-item.assistant .content h1,
.msg-item.assistant .content h2,
.msg-item.assistant .content h3 { margin:6px 0 4px; line-height:1.25; }
.msg-item.assistant .content p { margin:4px 0; }
.msg-item.assistant .content pre { background:#1e1e1e; color:#ddd; padding:8px 10px; border-radius:4px; overflow:auto; font-size:12px; }
.msg-item.assistant .content code.md-inline { background:#f2f2f2; padding:2px 4px; border-radius:3px; font-family:Consolas,Menlo,monospace; font-size:12px; }
.msg-item.assistant .content pre code { background:transparent; padding:0; }
.msg-item.assistant .content ul, .msg-item.assistant .content ol { margin:4px 0 4px 18px; padding:0; }
.msg-item.assistant .content li { margin:2px 0; }

</style>